package com.jasmine.bjstkserver.server.article.online;

import cn.hutool.core.util.StrUtil;
import com.jasmine.bjstkserver.core.config.exception.ArticleException;
import com.jasmine.bjstkserver.core.config.exception.BjsException;
import com.jasmine.bjstkserver.mapper.ArticleDraftMapper;
import com.jasmine.bjstkserver.mapper.ArticleMapper;
import com.jasmine.bjstkserver.server.article.ArticleConstants;
import com.jasmine.bjstkserver.server.article.draft.model.ArticleDraftEntity;
import com.jasmine.bjstkserver.server.article.draft.model.ArticleDraftRes;
import com.jasmine.bjstkserver.server.article.online.model.ArticleEntity;
import com.jasmine.bjstkserver.server.article.online.model.ArticleMindRes;
import com.jasmine.bjstkserver.server.article.online.model.ArticleReq;
import com.jasmine.core.constants.BjsConstants;
import com.jasmine.core.util.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author jasmineXz
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ArticleDraftMapper articleDraftMapper;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;


    /**
     * 文章列表
     * @param article 请求参数
     * @return 文章列表
     */
    @Override
    public List<ArticleDraftRes> findList(ArticleReq article) {
        return articleMapper.findList(article);
    }


    /**
     * 查询文章
     * @param article 查询条件
     * @return 文章
     */
    @Override
    public ArticleDraftRes findOne(ArticleReq article) {
        ArticleDraftRes art = (ArticleDraftRes) redisTemplate.opsForValue().get(BjsConstants.Redis.ART_INFO + article.getArticleId());
        if (null == art) {
            art = articleMapper.findOne(article);
            redisTemplate.opsForValue().set(BjsConstants.Redis.ART_INFO + article.getArticleId(),art);
        }
        return art;
    }


    /**
     * 发布文章,已存在文章可以重复发布
     * @param article 文章信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer publish(ArticleReq article) throws Exception {
        article.setContentType(ArticleConstants.CONTENT_ALL);
        ArticleDraftRes draft = articleDraftMapper.findOne(article);
        if (StrUtil.isBlank(draft.getContentMd())) {
            throw new ArticleException("无内容的文章无法发布");
        }

        Integer result;
        if (0 == articleMapper.findCount(article.getArticleId(),null)) {
            ArticleDraftEntity updDraft = new ArticleDraftEntity();
            updDraft.setArticleId(draft.getArticleId());
            updDraft.setPubState(ArticleConstants.PUB_YES);
            articleDraftMapper.updateByPrimaryKeySelective(updDraft);
            result = articleMapper.insertSelective(BeanUtil.copyObject(draft,ArticleEntity.class));
        } else {
            result = this.rePublish(BeanUtil.copyObject(draft,ArticleEntity.class));
        }
        redisTemplate.delete(BjsConstants.Redis.ART_INFO + article.getArticleId());
        return result;
    }


    /**
     * 再次发布
     * @param article 文章信息
     * @return 影响行数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer rePublish(ArticleEntity article) {
        ArticleDraftEntity updDraft = new ArticleDraftEntity();
        updDraft.setArticleId(article.getArticleId());
        updDraft.setPubState(ArticleConstants.PUB_YES);
        updDraft.setVersionCloud(article.getVersion());
        articleDraftMapper.updateByPrimaryKeySelective(updDraft);

        ArticleEntity upd = new ArticleEntity();
        upd.setArticleId(article.getArticleId());
        upd.setContentMd(article.getContentMd());
        upd.setContentHtml(article.getContentHtml());
        upd.setVersion(article.getVersion());
        upd.setUpdTime(LocalDateTime.now());
        return articleMapper.updateByPrimaryKeySelective(upd);
    }


    /**
     * 撤销发布
     * 清除缓存
     * @param article 文章ID
     * @return 影响行数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer abolish(ArticleReq article) {
        if (article == null || article.getArticleId() == null) {
            throw new IllegalArgumentException("参数错误");
        }
        ArticleDraftEntity draft = new ArticleDraftEntity();
        draft.setArticleId(article.getArticleId());
        draft.setPubState(ArticleConstants.PUB_NO);
        Integer result = articleDraftMapper.updateByPrimaryKeySelective(draft);
        redisTemplate.delete(BjsConstants.Redis.ART_INFO + article.getArticleId());
        return result;
    }


    @Override
    public synchronized Integer applaud(ArticleReq article) {
        articleMapper.applaudIncrease(article.getArticleId());
        return null;
    }


    @Override
    public synchronized Integer clickIncrease(Integer articleId) {
        return articleMapper.clickIncrease(articleId);
    }


    @Override
    public synchronized Integer viewIncrease(Integer articleId) {
        return articleMapper.viewIncrease(articleId);
    }




    /* ------------------- 统计 ------------------- */




    /**
     * 文章树状统计
     * @param article 文章信息
     * @param type 类型 [art:=包含文章名;folder或空:只有文件夹]
     * @return 文章文件夹树状列表
     */
    @Override
    public List<ArticleMindRes> findStatisTree(ArticleReq article,String type) {
        List<ArticleMindRes> all = articleMapper.findStatisTree(article,type);

        List<ArticleMindRes> root = all.stream().filter(p -> "f0".equals(p.getPid())).collect(Collectors.toList());
        root.parallelStream().forEach(item -> setChild(item, all));
        return root;
    }

    @Override
    public Map<String, Long> findStatisNum(ArticleReq article) {
        return articleMapper.findStatisNum(article);
    }





















    /**
     * 构造树状列表
     */
    private void setChild(ArticleMindRes p, List<ArticleMindRes> folder) {
        //将集合中自己去除
        List<ArticleMindRes> child =
                folder.parallelStream()
                        .filter(a -> a.getPid().equals(p.getId()))
                        .collect(Collectors.toList());
        p.setChildren(child);
        if (!CollectionUtils.isEmpty(child)) {
            child.parallelStream().forEach(c -> {
                setChild(c, folder); //递归设置子元素
            });
        }
    }

}
